﻿using System;
using System . Collections . Generic;
using System . Linq;
using Windows . Foundation . Collections;

namespace WenceyWang.RichMan4L.App . Common
{
    /// <summary>
    /// Implementation of IObservableMap that supports reentrancy for use as a default view
    /// model.
    /// </summary>
    public class ObservableDictionary : IObservableMap<string , object>
    {
        private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<string>
        {
            public ObservableDictionaryChangedEventArgs ( CollectionChange change , string key )
            {
                this . CollectionChange = change;
                this . Key = key;
            }

            public CollectionChange CollectionChange { get; private set; }
            public string Key { get; private set; }
        }

        private Dictionary<string, object> _dictionary = new Dictionary<string, object>();
        public event MapChangedEventHandler<string, object> MapChanged;

        private void InvokeMapChanged ( CollectionChange change , string key )
        {
            var eventHandler = MapChanged;
            if ( eventHandler != null )
            {
                eventHandler ( this , new ObservableDictionaryChangedEventArgs ( change , key ) );
            }
        }

        public void Add ( string key , object value )
        {
            this . _dictionary . Add ( key , value );
            this . InvokeMapChanged ( CollectionChange . ItemInserted , key );
        }

        public void Add ( KeyValuePair<string , object> item )
        {
            this . Add ( item . Key , item . Value );
        }

        public bool Remove ( string key )
        {
            if ( this . _dictionary . Remove ( key ) )
            {
                this . InvokeMapChanged ( CollectionChange . ItemRemoved , key );
                return true;
            }
            return false;
        }

        public bool Remove ( KeyValuePair<string , object> item )
        {
            object currentValue;
            if ( this . _dictionary . TryGetValue ( item . Key , out currentValue ) &&
                Object . Equals ( item . Value , currentValue ) && this . _dictionary . Remove ( item . Key ) )
            {
                this . InvokeMapChanged ( CollectionChange . ItemRemoved , item . Key );
                return true;
            }
            return false;
        }

        public object this [ string key ]
        {
            get
            {
                return this . _dictionary [ key ];
            }
            set
            {
                this . _dictionary [ key ] = value;
                this . InvokeMapChanged ( CollectionChange . ItemChanged , key );
            }
        }

        public void Clear ( )
        {
            var priorKeys = this._dictionary.Keys.ToArray();
            this . _dictionary . Clear ( );
            foreach ( var key in priorKeys )
            {
                this . InvokeMapChanged ( CollectionChange . ItemRemoved , key );
            }
        }

        public ICollection<string> Keys
        {
            get { return this . _dictionary . Keys; }
        }

        public bool ContainsKey ( string key )
        {
            return this . _dictionary . ContainsKey ( key );
        }

        public bool TryGetValue ( string key , out object value )
        {
            return this . _dictionary . TryGetValue ( key , out value );
        }

        public ICollection<object> Values
        {
            get { return this . _dictionary . Values; }
        }

        public bool Contains ( KeyValuePair<string , object> item )
        {
            return this . _dictionary . Contains ( item );
        }

        public int Count
        {
            get { return this . _dictionary . Count; }
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public IEnumerator<KeyValuePair<string , object>> GetEnumerator ( )
        {
            return this . _dictionary . GetEnumerator ( );
        }

        System . Collections . IEnumerator System . Collections . IEnumerable.GetEnumerator ( )
        {
            return this . _dictionary . GetEnumerator ( );
        }

        public void CopyTo ( KeyValuePair<string , object> [ ] array , int arrayIndex )
        {
            int arraySize = array.Length;
            foreach ( var pair in this . _dictionary )
            {
                if ( arrayIndex >= arraySize ) break;
                array [ arrayIndex++ ] = pair;
            }
        }
    }
}
